home *** CD-ROM | disk | FTP | other *** search
/ Apple Developer Connection 1998 Fall: Game Toolkit / Disc.iso / SDKs / Third Party SDKs / ATI RAVE SDK / Samples / Strip Test / src / strip.cpp
Encoding:
C/C++ Source or Header  |  1998-07-07  |  29.1 KB  |  1,297 lines  |  [TEXT/CWIE]

  1. /*
  2.  *    Name:            torus.cpp
  3.  *     
  4.  *  Author:            Chris Bentley 1/17/98, ATI Research Inc. Marlborough, MA
  5.  *
  6.  *    Description:    a simple test app that demonstrates the benefit of
  7.  *                    using the RAVE strip/fan triangle interface over using 
  8.  *                    individual discrete triangles.  Essentially strips/fans
  9.  *                    are over twice as fast as individual triangles.
  10.  *
  11.  *    Revision History
  12.  *
  13.  *        1/19/98    CLB    - initial version 1.0
  14.  *        1/19/98    CLB    - added moving context when window dragged
  15.  *        1/19/98    CLB    - bumped version to 1.1
  16.  *        1/19/98    CLB    - changed output to render time + actual fps
  17.  *        1/20/98    CLB    - bumped version to 1.2
  18.  *        1/20/98    CLB    - fixed moving window + RAVE context rect
  19.  *        2/18/98    CLB    - bumped version to 1.3
  20.  *        2/18/98    CLB    - changed non-strip version to call QADrawVTexture( ..., kQAVertexMode_Tri )
  21.  *        3/8/98    CLB    - bumped version to 1.4
  22.  *        3/8/98    CLB    - added support for draagging between multiple monitors
  23.  *
  24.  */
  25. /****************************************************************/
  26. /* headers                                                        */
  27. /****************************************************************/
  28. #include <stdio.h>
  29. #include <stdlib.h>
  30. #include <string.h>
  31. #include <math.h>
  32. #include <Timer.h>
  33. #include "RAVE.h"
  34. #include "macros.h"
  35. #include "matrix.h"
  36.  
  37. /****************************************************************/
  38. /* defines                                                        */
  39. /****************************************************************/
  40. #define LEFT                20
  41. #define TOP                    40
  42. #define WIDTH                600
  43. #define HEIGHT                400
  44.  
  45. #define BRICK_RES_ID        128
  46. #define SUN_RES_ID            129
  47.  
  48. #define MBAR_RES_ID            128
  49.  
  50. #define APPLE_MENU_ID        128
  51. #define FILE_MENU_ID        129
  52. #define CONTROL_MENU_ID        130
  53. #define ENGINE_MENU_ID        131
  54.  
  55. #define QUIT_ITEM            1
  56.  
  57. #define TRI_ITEM            1
  58. #define STRIP_ITEM            2
  59. #define TEX_ALPHA_ITEM        3
  60. #define NO_TEX_ALPHA_ITEM    4
  61.  
  62. #define TRIANGLE            0
  63. #define STRIP                1
  64. #define NUM_STEPS            36
  65. #define MAX_WORLD_VERTS        (NUM_STEPS+1)*(NUM_STEPS+1)
  66. #define MAX_SCREEN_VERTS    (NUM_STEPS+1)*(NUM_STEPS+1)*6
  67.  
  68. #define MAX_ENGINE            5
  69.  
  70. /*
  71.  * macro to load fields of TQAVTexture
  72.  */
  73. #define ST( _v,_x,_y,_z,_invW,_a,_r,_g,_b,_uOverW,_vOverW,_kd_r,_kd_g,_kd_b,_ks_r,_ks_g,_ks_b ) \
  74. {                                                             \
  75.     (_v).x         = (_x);                                        \
  76.     (_v).y         = (_y);                                        \
  77.     (_v).z         = (_z);                                        \
  78.     (_v).invW     = (_invW);                                    \
  79.     (_v).a         = (_a);                                        \
  80.     (_v).r         = (_r);                                        \
  81.     (_v).g         = (_g);                                        \
  82.     (_v).b         = (_b);                                        \
  83.     (_v).uOverW = (_uOverW);                                \
  84.     (_v).vOverW = (_vOverW);                                \
  85.     (_v).kd_r     = (_kd_r);                                    \
  86.     (_v).kd_g     = (_kd_g);                                    \
  87.     (_v).kd_b     = (_kd_b);                                    \
  88.     (_v).ks_r     = (_ks_r);                                    \
  89.     (_v).ks_g     = (_ks_g);                                    \
  90.     (_v).ks_b     = (_ks_b);                                    \
  91. }
  92.  
  93. #define SetRect( R, l, t, r, b )    (R)->left = (l), (R)->top = (t), (R)->right = (r), (R)->bottom = (b)
  94.  
  95. /*
  96.  * utility macros
  97.  */
  98. #define USHRT_MAX                    65535U
  99. #define ONE_SECOND                    1000000
  100. #define MILLIONTHS                    0.000001F
  101. #define INV_360                        0.002777777
  102. #define rand()                        ((32767+Random()) * 1.0/65536.0)
  103.  
  104. /****************************************************************/
  105. /* typedefs                                                        */
  106. /****************************************************************/
  107. typedef unsigned char UINT8;
  108. typedef unsigned short UINT16;
  109. typedef long INT32;
  110. typedef unsigned long UINT32;
  111.  
  112. typedef struct object {
  113.     int                num_verts;
  114.     int                num_rave_verts;
  115.     int                num_strips;
  116.     int                num_verts_per_strip;
  117.     VECT            world[MAX_WORLD_VERTS];
  118.     VECT            tex[MAX_WORLD_VERTS];
  119.     VECT            screen[MAX_WORLD_VERTS];
  120.     TQAVTexture        verts[MAX_SCREEN_VERTS];
  121. } OBJECT;
  122.  
  123. /****************************************************************/
  124. /* prototypes                                                    */
  125. /****************************************************************/
  126. /*
  127.  * initialization functions
  128.  */
  129. void InitMac( void );
  130. int InitWindow( void );
  131. int InitRAVE( void );
  132. TQAEngine *FindEngine( TQADevice *device );
  133. GDHandle FindWindowDevice( WindowPtr pWin );
  134. void FindWindowContentRect( WindowPtr pWin, Rect *r );
  135. int SetupRAVE( void );
  136. int SetupRAVETex( void );
  137. void MenuBarInit( void );
  138.  
  139. /*
  140.  * Event handling functions
  141.  */
  142. void EventLoop( void );
  143. void HandleMouseDown( EventRecord *pevent );
  144. void HandleMenuChoice( INT32 i32menuChoice );
  145. void HandleAppleChoice( UINT32 u32TheItem );
  146. void HandleFileChoice( UINT32 u32TheItem );
  147. void HandleControlChoice( UINT32 u32TheItem );
  148. void AdjustControlMenu( void );
  149. void HandleEngineChoice( UINT32 u32TheItem );
  150.  
  151. /*
  152.  * utility functions
  153.  */
  154. void Cleanup( void );
  155. void DisplayString( int x, int y, char *str );
  156. UINT32 MicrosecondCount( void );
  157. int LoadImageFromResource(     short resID, UINT8 depth, UINT8 alpha, 
  158.                             TQAImage *map, TQAImagePixelType *pixelType );
  159.                             
  160. /*
  161.  * 3D object functions
  162.  */
  163. void redraw( void );
  164. void gen_torus( float radius1, float radius2, OBJECT *obj );
  165. void convert( OBJECT *obj, int mode );
  166. void transform( OBJECT *obj );
  167. void render( OBJECT *obj );
  168.  
  169. /*
  170.  * matrix functions
  171.  */
  172. void matrix_mult( MATRIX mat1, MATRIX mat2, MATRIX result );
  173. void vect_matrix_mult( VECT pt, MATRIX mat, VECT result );
  174. void load_matrix_rows( MATRIX R, VECT row1, VECT row2, VECT row3 );
  175. void set_view_matrix( MATRIX V, VECT lookat, VECT up, VECT eye, Rect *WinRect );
  176. void rotate_about_axis( VECT axis, FLOAT32 angle, MATRIX M );
  177.  
  178. /****************************************************************/
  179. /* global variables                                                */
  180. /****************************************************************/
  181. /*
  182.  * RAVE variables
  183.  */
  184. GDHandle        gGDevice;
  185. TQADevice       gDevice;
  186. TQAEngine       *gEngine;
  187. TQADrawContext  *gDrawContext;
  188. TQATexture         *gpTex;
  189. TQABitmap         *gpBit;
  190. TQAImage         gImageTex;
  191. TQAImage         gImageBit;
  192. TQAImagePixelType pixelType;
  193. unsigned long    gflags = kQAContext_DoubleBuffer;
  194. TQARect         gRect     = { LEFT, LEFT+WIDTH, TOP, TOP+HEIGHT };
  195. TQAEngine         *EngineList[MAX_ENGINE] = { NULL, NULL, NULL, NULL, NULL };
  196. char            EngineNames[MAX_ENGINE][100];
  197. unsigned long    gEngineID = 0;
  198.  
  199. /*
  200.  * window variables
  201.  */
  202. MenuHandle        gAppleMenu;
  203. MenuHandle        gFileMenu;
  204. MenuHandle        gControlMenu;
  205. MenuHandle        gEngineMenu;
  206. Boolean         gbDone = false;
  207. Boolean            gbTexAlpha = true;
  208. Boolean            gbATIcard = false;
  209. int                gNumEngines = 0;
  210. WindowPtr        winPtr = NULL;
  211. Rect            winRect = { TOP, LEFT, TOP+HEIGHT, LEFT+WIDTH };
  212. RGBColor        BLACK = { 0, 0, 0 };
  213. GWorldPtr        newGW;
  214. char             str[256];
  215. OBJECT            torus;
  216.  
  217. /*
  218.  * matrix utility variables
  219.  */
  220. VECT     _util_vect;    
  221. FLOAT32    _util_FLOAT321;
  222. FLOAT32    _util_FLOAT322;
  223. MATRIX    VPN;
  224. MATRIX    R;
  225. VECT     lookat    = { 0, 0, 0, 1 };
  226. VECT     up        = { 0, 1, 0, 1 };
  227. VECT     eye        = { 0, 0, -10,1 };
  228. VECT    axis     = { 0.3, 1, 0.2, 0 };
  229. VECT    axis0;
  230. int        mode    = TRIANGLE; //STRIP;
  231.  
  232. /****************************************************************/
  233. /* code                                                            */
  234. /****************************************************************/
  235. /*
  236.  * Function:    main()
  237.  *
  238.  */
  239. void main( void )
  240. {
  241.     /*
  242.      * initialize Toolbox + window
  243.      */
  244.     InitMac();
  245.     
  246.     if( !InitWindow() || !InitRAVE() || !SetupRAVE() )
  247.     {
  248.         Cleanup();
  249.         return;
  250.     }
  251.  
  252.     set_view_matrix( VPN, lookat, up, eye, &winRect );
  253.     rotate_about_axis( axis, DEG2RAD(5), R );
  254.     gen_torus( 2.0, 4.0, &torus );
  255.     redraw();
  256.     
  257.     EventLoop();
  258.         
  259.     /*
  260.      * end
  261.      */
  262.     Cleanup();
  263. }
  264.  
  265. /*
  266.  * Function:    InitMac()
  267.  *
  268.  */
  269. void InitMac( void )
  270. {
  271.     OSErr        error;
  272.     SysEnvRec    theWorld;
  273.         
  274.     /*
  275.      *    Test the computer to be sure we can do color.  
  276.      *    If not we would crash, which would be bad.  
  277.      *    If we can’t run, just beep and exit.
  278.      */
  279.     error = SysEnvirons( 1, &theWorld );
  280.     if( theWorld.hasColorQD == false ) 
  281.         ExitToShell();
  282.     
  283.     /* 
  284.      * Initialize all the needed managers. 
  285.      */
  286.     InitGraf( &qd.thePort );
  287.     InitFonts();
  288.     InitWindows();
  289.     InitMenus();
  290.     TEInit();
  291.     InitDialogs( NULL );
  292.     InitCursor();
  293.         
  294.     GetDateTime((unsigned long*) &qd.randSeed);
  295.     
  296.     MenuBarInit();
  297. }
  298.  
  299. /*
  300.  * Function:    InitWindow()
  301.  *
  302.  */
  303. int InitWindow( void )
  304. {
  305.     if( (winPtr = NewCWindow( NULL, &winRect, "\pStrip/Triangle Test", true, 
  306.                                  noGrowDocProc, (WindowPtr)-1, false, 0 )) == NULL )
  307.     {
  308.         printf( "ERROR: opening window\n" );
  309.         return( false );
  310.     }
  311.     
  312.     return( true );
  313. }
  314.  
  315. /*
  316.  * Function:    InitRAVE()
  317.  *
  318.  */
  319. int InitRAVE( void )
  320. {
  321.     Rect    r;
  322.     
  323.     if( (gGDevice =  FindWindowDevice(winPtr)) == NULL )
  324.     {
  325.          printf( "ERROR: No monitors found\n" );
  326.          return( false );
  327.     }
  328.  
  329.     gDevice.deviceType         = kQADeviceGDevice;
  330.     gDevice.device.gDevice     = gGDevice;
  331.     
  332.     if( (gEngine = FindEngine( &gDevice )) == NULL )
  333.     {
  334.          printf( "ERROR: No Engine available\n" );
  335.          return( false );
  336.     }
  337.  
  338.     if( QAEngineCheckDevice( gEngine, &gDevice ) )
  339.     {
  340.          printf( "ERROR: EngineCheckDevice failed\n" );
  341.          return( false );
  342.     }
  343.  
  344.     FindWindowContentRect( winPtr, &r );
  345.     OffsetRect( &r, -(**gGDevice).gdRect.left, -(**gGDevice).gdRect.top );
  346.     
  347.     gRect.left         = r.left; 
  348.     gRect.top          = r.top;  
  349.     gRect.right      = r.right;
  350.     gRect.bottom     = r.bottom;
  351.         
  352.     return( true );
  353. }
  354.  
  355. void FindWindowContentRect( WindowPtr pWin, Rect *r )
  356. {
  357.     GrafPtr    oldPort;
  358.     Point    leftTop;
  359.     Point    rightBot;
  360.     
  361.     GetPort( &oldPort );
  362.     
  363.     SetPort( pWin );
  364.     SetPt( &leftTop, pWin->portRect.left, pWin->portRect.top );
  365.     SetPt( &rightBot, pWin->portRect.right, pWin->portRect.bottom );
  366.     
  367.     LocalToGlobal( &leftTop );
  368.     LocalToGlobal( &rightBot );
  369.     
  370.     SetRect( r, leftTop.h, leftTop.v, rightBot.h, rightBot.v );
  371.     
  372.     SetPort( oldPort );
  373. }
  374.  
  375. /*
  376.  * Function:    FindWindowDevice()
  377.  *
  378.  */
  379. GDHandle FindWindowDevice( WindowPtr pWin )
  380. {
  381.     GDHandle    hDevice;
  382.     Rect        rWin;
  383.     Rect        intersect;
  384.     
  385.     if( pWin == NULL )
  386.         return( NULL );
  387.         
  388.     rWin = ((*(((WindowPeek)pWin)->strucRgn))->rgnBBox);
  389.     
  390.     for( hDevice = GetDeviceList(); 
  391.          hDevice; 
  392.          hDevice = GetNextDevice(hDevice) )
  393.     {
  394.         /*
  395.          * test for active monitors that entirely contain rect
  396.          */
  397.         if( TestDeviceAttribute(hDevice, screenDevice) &&
  398.             TestDeviceAttribute(hDevice, screenActive) &&
  399.             SectRect(&rWin, &((*hDevice)->gdRect), &intersect) &&
  400.             EqualRect(&rWin, &intersect) )
  401.         {
  402.             return( hDevice );
  403.         }    
  404.     }
  405.  
  406.     return( NULL );    
  407. }
  408.  
  409. TQAEngine *FindEngine( TQADevice *device )
  410. {
  411.     TQAEngine     *tmpEngine;
  412.     UINT32        vendorID;
  413.     char        Response[200];
  414.     int            i, len;
  415.     int            saveEngineID;
  416.     Str255        menuStr;
  417.     MenuHandle    menuHndl    = gEngineMenu;
  418.     
  419.     saveEngineID     = gEngineID;
  420.     gEngineID        = 0;
  421.     
  422.     for( i = 0; i < gNumEngines; i++ )
  423.     {
  424.         CheckItem( gEngineMenu, i+1, false );
  425.         DisableItem( gEngineMenu, i+1 );
  426.     }
  427.     
  428.     /*
  429.      * list all RAVE engines
  430.      */
  431.     for( tmpEngine = QADeviceGetFirstEngine(device);
  432.          tmpEngine;
  433.          tmpEngine = QADeviceGetNextEngine(device, tmpEngine) )
  434.     {
  435.         QAEngineGestalt( tmpEngine, kQAGestalt_ASCIIName, Response );
  436.         
  437.         /*
  438.          * see if engine is already in list
  439.          */
  440.         for( i = 0; i < gNumEngines; i++ )
  441.         {
  442.             if( strcmp(Response, EngineNames[i]) == 0 )
  443.             {
  444.                 EngineList[i] = tmpEngine;
  445.                 EnableItem( gEngineMenu, i+1 );
  446.                 
  447.                 if( i == saveEngineID )
  448.                     gEngineID = i;
  449.                 break;
  450.             }
  451.         }
  452.  
  453.         /*
  454.          * if engine is not already in list add it
  455.          */        
  456.         if( i == gNumEngines )
  457.         {
  458.             EngineList[gNumEngines] = tmpEngine;
  459.             strcpy( EngineNames[gNumEngines], Response );
  460.         
  461.             menuStr[0] = strlen( Response );
  462.             strcpy( (char *)(menuStr+1), Response );
  463.         
  464.             AppendMenu( gEngineMenu, menuStr );
  465.             
  466.             if( ++gNumEngines == MAX_ENGINE )
  467.                 break;
  468.         }
  469.     }    
  470.     
  471.     if( gEngineID >= gNumEngines )
  472.         gEngineID = 0;
  473.     
  474.     CheckItem( gEngineMenu, gEngineID+1, true );
  475.  
  476.     QAEngineGestalt( EngineList[gEngineID], kQAGestalt_VendorID, &vendorID );        
  477.     gbATIcard     = (vendorID == 1);
  478.  
  479.     return( EngineList[gEngineID] );
  480. }
  481.  
  482. int SetupRAVE( void )
  483. {    
  484.     if( !InitRAVE() )
  485.         return( false );
  486.         
  487.     /*
  488.      * create a draw context + set background color for clearing
  489.      */
  490.     if( QADrawContextNew(&gDevice,&gRect,0,gEngine,gflags,&gDrawContext) != kQANoErr )
  491.     {
  492.          printf( "ERROR: Context create failed\n" );
  493.          return( false );
  494.     }
  495.     
  496.     QASetFloat( gDrawContext, kQATag_ColorBG_a, 1.0 );
  497.     QASetFloat( gDrawContext, kQATag_ColorBG_r, 1.0 );
  498.     QASetFloat( gDrawContext, kQATag_ColorBG_g, 0.0 );
  499.     QASetFloat( gDrawContext, kQATag_ColorBG_b, 0.0 );
  500.  
  501.     return( SetupRAVETex() );
  502. }
  503.         
  504. int SetupRAVETex( void )
  505. {
  506.     /*
  507.      * load image for texture
  508.      */    
  509.     if( !LoadImageFromResource(SUN_RES_ID, 16, gbTexAlpha, &gImageTex, &pixelType) )
  510.     {
  511.          printf( "ERROR: loading bitmap resource failed\n" );
  512.          return( false );
  513.     }    
  514.     
  515.     /*
  516.      * register texture with RAVE
  517.      */
  518.     QATextureNew( gEngine, kQATexture_None, pixelType, &gImageTex, &gpTex );
  519.     if( gpTex == NULL )
  520.     {
  521.          printf( "ERROR: RAVE bitmap registration failed\n" );
  522.          return( false );
  523.     }    
  524.     
  525.     QATextureDetach( gEngine, gpTex );
  526.     DisposeGWorld( newGW );
  527.     
  528.     /*
  529.      * set current texture
  530.      */
  531.     QASetPtr( gDrawContext, kQATag_Texture, gpTex );
  532.     
  533.     return( true );
  534. }
  535.  
  536. void MenuBarInit( void )
  537. {
  538.     Handle        mBarHndl;
  539.     
  540.     mBarHndl = GetNewMBar( MBAR_RES_ID );
  541.     SetMenuBar( mBarHndl );
  542.     
  543.     gAppleMenu        = GetMenu( APPLE_MENU_ID );
  544.     gFileMenu        = GetMenu( FILE_MENU_ID );
  545.     gControlMenu    = GetMenu( CONTROL_MENU_ID );
  546.     gEngineMenu        = GetMenu( ENGINE_MENU_ID );
  547.     
  548.     AppendResMenu( gAppleMenu, 'DRVR' );
  549.     
  550.     DrawMenuBar();
  551.     
  552.     AdjustControlMenu();
  553. }
  554.  
  555. void EventLoop( void )
  556. {
  557.     EventRecord        event;
  558.     
  559.     while( !gbDone )
  560.     {    
  561.         WaitNextEvent( everyEvent, &event, 60L, NULL );
  562.         
  563.         switch( event.what )
  564.         {                
  565.             case mouseDown:        HandleMouseDown( &event );        break;
  566.             case updateEvt:                                        break;
  567.             case nullEvent:                                        break;
  568.             default:                                            break;
  569.         }
  570.     }
  571. }
  572.  
  573. void HandleMouseDown( EventRecord *pevent )
  574. {
  575.     WindowPtr    pWin;
  576.     
  577.     switch( FindWindow( pevent->where, &pWin ) )
  578.     {            
  579.         case inMenuBar:        HandleMenuChoice( MenuSelect( pevent->where ) );            break;    
  580.         case inSysWindow:    SystemClick( pevent, pWin );                                break;    
  581.         case inGoAway:        gbDone = (TrackGoAway(pWin, pevent->where) == true);        break;
  582.         case inContent:                                                                    break;
  583.         case inDrag:        DragWindow( pWin, pevent->where, &qd.screenBits.bounds );
  584.                             Cleanup();
  585.     
  586.                             if( !SetupRAVE() )
  587.                                 Cleanup();
  588.         
  589.                             redraw();
  590.                             break;
  591.         
  592.         default:                                                                        break;
  593.     }
  594. }
  595.  
  596. void HandleMenuChoice( INT32 i32menuChoice )
  597. {
  598.     if( i32menuChoice == 0 )
  599.         return;
  600.             
  601.     switch( HiWord( i32menuChoice ) )
  602.     {
  603.         case APPLE_MENU_ID:        HandleAppleChoice( LoWord(i32menuChoice) );        break;
  604.         case FILE_MENU_ID:        HandleFileChoice( LoWord(i32menuChoice) );        break;
  605.         case CONTROL_MENU_ID:    HandleControlChoice( LoWord(i32menuChoice) );    break;
  606.         case ENGINE_MENU_ID:    HandleEngineChoice( LoWord(i32menuChoice) );    break;
  607.         default:                                                                break;
  608.     } 
  609.  
  610.     HiliteMenu( 0 );     
  611. }
  612.  
  613. void HandleAppleChoice( UINT32 u32TheItem )
  614. {
  615.     Str255        strAccName;        
  616.     
  617.     switch( u32TheItem )
  618.     {
  619.         default:            GetMenuItemText( gAppleMenu, u32TheItem, strAccName );
  620.                             OpenDeskAcc( strAccName );            
  621.                             break;
  622.     }
  623. }
  624.  
  625. void HandleFileChoice( UINT32 u32TheItem )
  626. {
  627.     switch( u32TheItem )
  628.     {
  629.         case QUIT_ITEM:        gbDone = true;        break;
  630.         default:                                break;
  631.     }
  632. }
  633.  
  634. void HandleControlChoice( UINT32 u32TheItem )
  635. {
  636.     switch( u32TheItem )
  637.     {
  638.         case TRI_ITEM:            
  639.             mode = TRIANGLE; 
  640.             break;
  641.             
  642.         case STRIP_ITEM:        
  643.             mode = STRIP;     
  644.             break;
  645.             
  646.         case TEX_ALPHA_ITEM:    
  647.             gbTexAlpha = true;
  648.             
  649.             if( gpTex )
  650.                 QATextureDelete( gEngine, gpTex );
  651.     
  652.             if( !SetupRAVETex() )
  653.                 Cleanup();
  654.             break;
  655.             
  656.         case NO_TEX_ALPHA_ITEM:    
  657.             gbTexAlpha = false;
  658.             
  659.             if( gpTex )
  660.                 QATextureDelete( gEngine, gpTex );
  661.  
  662.             if( !SetupRAVETex() )
  663.                 Cleanup();
  664.             break;
  665.             
  666.         default:                                                
  667.             break;
  668.     }
  669.  
  670.     AdjustControlMenu();
  671.     
  672.     redraw();
  673. }
  674.  
  675. void AdjustControlMenu( void )
  676. {
  677.     CheckItem( gControlMenu, TRI_ITEM,                 mode == TRIANGLE     );    
  678.     CheckItem( gControlMenu, STRIP_ITEM,             mode == STRIP         );
  679.     CheckItem( gControlMenu, TEX_ALPHA_ITEM,         gbTexAlpha             );    
  680.     CheckItem( gControlMenu, NO_TEX_ALPHA_ITEM,     !gbTexAlpha         );    
  681. }
  682.  
  683. void HandleEngineChoice( UINT32 u32TheItem )
  684. {
  685.     UINT32    vendorID;
  686.     
  687.     for( int i = 1; i <= gNumEngines; i++ )
  688.         CheckItem( gEngineMenu, i, false );
  689.  
  690.     gEngineID    = u32TheItem-1;
  691.     gEngine     = EngineList[gEngineID];
  692.     
  693.     QAEngineGestalt( gEngine, kQAGestalt_VendorID, &vendorID );        
  694.     gbATIcard     = (vendorID == 1);
  695.     
  696.     if( QAEngineCheckDevice( gEngine, &gDevice ) )
  697.          printf( "ERROR: EngineCheckDevice failed\n" );
  698.  
  699.     CheckItem( gEngineMenu, u32TheItem, true );
  700.     
  701.     Cleanup();
  702.     
  703.     if( !SetupRAVE() )
  704.         Cleanup();
  705.     
  706.     redraw();
  707. }
  708.  
  709. /*
  710.  * Function:    Cleanup()
  711.  *
  712.  */
  713. void Cleanup( void )
  714. {
  715.     if( gpTex )
  716.         QATextureDelete( gEngine, gpTex );
  717.  
  718.     if( gDrawContext )
  719.         QADrawContextDelete( gDrawContext );
  720. }
  721.  
  722. /*
  723.  *    Function:    DisplayString()
  724.  *
  725.  */
  726. void DisplayString( int x, int y, char *str )
  727. {
  728.     if( !winPtr )
  729.         return;
  730.             
  731.     SetPort( winPtr );
  732.     RGBForeColor( &BLACK );
  733.     MoveTo( x, y );
  734.     
  735.     str[0] = strlen( str+1 );
  736.     DrawString( (const unsigned char *)str );
  737. }
  738.  
  739. /*
  740.  *    Function:    MicrosecondCount()
  741.  *
  742.  */
  743. UINT32 MicrosecondCount( void )
  744. {    
  745.     UnsignedWide currentCount;
  746.     
  747.     Microseconds(¤tCount);
  748.     
  749.     return( currentCount.lo );
  750. }
  751.  
  752. /*
  753.  *    Function:    LoadImageFromResource()
  754.  *
  755.  */
  756. int LoadImageFromResource(     short resID, UINT8 depth, UINT8 alpha, 
  757.                             TQAImage *map, TQAImagePixelType *pixelType )
  758. {
  759.     PicHandle        hPict;
  760.     Rect            pictRect;
  761.     GDHandle        saveGD;
  762.     GWorldPtr        saveGW;
  763.     PixMapHandle    pixHndl;
  764.     PixMapPtr        pixPtr;
  765.  
  766.     /*
  767.      * determine target pixel type
  768.      */
  769.     switch( depth )
  770.     {
  771.         case 8:     *pixelType = kQAPixel_CL8;                                  break;
  772.         case 16: *pixelType = (alpha) ? kQAPixel_ARGB16 : kQAPixel_RGB16; break;
  773.         case 32: *pixelType = (alpha) ? kQAPixel_ARGB32 : kQAPixel_RGB32; break;
  774.         default: return( false );
  775.     }
  776.  
  777.     /*
  778.      * load PICT resource and get bounding rect
  779.      */    
  780.     if( (hPict = GetPicture( resID )) == NULL )
  781.         return( false );
  782.     
  783.     pictRect = (**hPict).picFrame;
  784.  
  785.     /*
  786.      * setup GWorld to draw pict into
  787.      */     
  788.     GetGWorld( &saveGW, &saveGD );
  789.     
  790.     if( NewGWorld(&newGW, depth, &pictRect, NULL, NULL, NULL) != noErr )
  791.     {
  792.         ReleaseResource( (Handle)hPict );
  793.         return( false );
  794.     }
  795.     
  796.     LockPixels( newGW->portPixMap );
  797.     SetGWorld( newGW, NULL );
  798.     
  799.     DrawPicture(hPict, &pictRect );
  800.  
  801.     /*
  802.      * setup TQAImage struct with GWorld pixmap data
  803.      */    
  804.     pixHndl         = GetGWorldPixMap( newGW );        
  805.     pixPtr            = *pixHndl;
  806.     map->width         = pictRect.right - pictRect.left;
  807.     map->height     = pictRect.bottom - pictRect.top;
  808.     map->rowBytes    = (UINT32)(pixPtr->rowBytes & 0x7fff);
  809.     map->pixmap        = GetPixBaseAddr( pixHndl );
  810.  
  811.     /*
  812.      * Hack to demo sprite with alpha transparency -
  813.      * detect white pixels (in 'Sun' PICT from Scrapbook)
  814.      * and set their alpha bit to 0 for transparency
  815.      */        
  816.     if( alpha )
  817.     {
  818.         UINT8    *u8ptr = (UINT8 *)map->pixmap;
  819.         UINT16    *u16ptr;
  820.         
  821.         for( int y = 0; y < map->height; y++ )
  822.         {
  823.             u16ptr    = (UINT16 *)u8ptr;
  824.             
  825.             for( int x = 0; x < map->width; x++ )
  826.             {
  827.                 if( (u16ptr[x] & 0x7FFF) == 0x7FFF )
  828.                     u16ptr[x] &= 0x8000;
  829.                 else
  830.                     u16ptr[x] |= 0x8000;
  831.             }
  832.             
  833.             u8ptr += map->rowBytes;
  834.         }
  835.     }
  836.     
  837.     /*
  838.      * free PICT resource, delete temp GWorld,
  839.      * and restore old GWorld
  840.      */    
  841.     ReleaseResource( (Handle)hPict );
  842.     SetGWorld( saveGW, saveGD );
  843.     
  844.     return( true );
  845. }
  846.  
  847. void redraw( void )
  848. {
  849.     UINT32    start, rstart, end;
  850.     UINT32    count = 0;
  851.     float    time, rtime, fps;
  852.     float    sum = 0.0, rsum = 0.0;
  853.  
  854.     while( !Button() )
  855.     {
  856.         start = MicrosecondCount();
  857.  
  858.         transform( &torus );
  859.         convert( &torus, mode );
  860.         
  861.         rstart = MicrosecondCount();
  862.         render( &torus );
  863.         
  864.         /*
  865.          * display frame rate
  866.          */
  867.         end     = MicrosecondCount();
  868.         time    = (float)MAX((end-start),1)*MILLIONTHS;
  869.         sum        += 1.0/time;
  870.         
  871.         rtime    = (float)MAX((end-rstart),1)*MILLIONTHS;
  872.         rsum    += rtime;
  873.         
  874.         count++;
  875.         sprintf( str+1, "verts = %d  tri = %d  strip = %d  render = %5.4fs  avg = %5.4fs  fps = %5.2f", 
  876.                        torus.num_rave_verts, 
  877.                        (mode == STRIP) ? torus.num_rave_verts-2*NUM_STEPS : torus.num_rave_verts/3, 
  878.                        torus.num_strips, rtime, rsum/count, sum/count );
  879.         DisplayString( 2, 10, str );
  880.     }
  881. }
  882.  
  883. /*
  884.  *     Function:    gen_torus()
  885.  *
  886.  *    Comments:    generate vertex data for torus.  First we generate
  887.  *                vertices around a circle of radius1.  Then we translate
  888.  *                this by radius2, and rotate all the points around the
  889.  *                vertical (Y) axis.
  890.  *                                    
  891.  *     Inputs:        radius1 - radius of circle cross-section of torus
  892.  *                radius2 - radius from center of doughnut to outer edge
  893.  *                obj        - pointer to 3D object to store vertex list                    
  894.  *                            
  895.  *     Returns:    none
  896.  */
  897. void gen_torus( float radius1, float radius2, OBJECT *obj )
  898. {
  899.     int     angle, ainc = 360/NUM_STEPS;
  900.     int        vert = 0;
  901.     float    r;
  902.     
  903.     /*
  904.      * generate points around circle for
  905.      * torus cross-section
  906.      */
  907.     for( angle = 0; angle <= 360; angle += ainc )
  908.     {
  909.         set_vect( obj->world[vert], radius1 * cos(DEG2RAD(angle)) + radius2, radius1 * sin(DEG2RAD(angle)), 0, 1 ); 
  910.         set_vect( obj->tex[vert], 0, 1.0 - CLAMP(angle*INV_360,0,1), 0, 0 );
  911.         vert++;
  912.     }
  913.     
  914.     /*
  915.      * sweep circle around vertical axis to generate
  916.      * entire torus as surface of revolution
  917.      */
  918.     for( angle = ainc; angle <= 360; angle += ainc )
  919.     {
  920.         for( int i = 0; i <= NUM_STEPS; i++ )
  921.         {
  922.             r =  obj->world[i][X];
  923.             set_vect( obj->world[vert], r * cos(DEG2RAD(angle)), obj->world[i][Y], r * sin(DEG2RAD(angle)), 1.0 );
  924.             set_vect( obj->tex[vert], CLAMP(angle*INV_360,0,1), obj->tex[i][1], 0, 0 );
  925.             vert++;
  926.         }
  927.     }
  928.     
  929.     obj->num_verts = vert;
  930. }
  931.     
  932. void convert( OBJECT *obj, int mode )
  933. {
  934.     TQAVTexture    *v = &obj->verts[0];
  935.     int            i, j;
  936.     int            n = 0;
  937.     int            col, ncol;
  938.     
  939.     obj->num_strips     = 0;
  940.     obj->num_rave_verts = 0;
  941.     
  942.     if( mode == STRIP )
  943.     {
  944.         for( j = 0; j < NUM_STEPS; j++ )
  945.         {
  946.             col = j*(NUM_STEPS+1);
  947.             ncol = col + (NUM_STEPS+1);
  948.  
  949.             for( i = 0; i <= NUM_STEPS; i++ )
  950.             {
  951.                 ST( *v, obj->screen[col+i][X], obj->screen[col+i][Y], obj->screen[col+i][Z], 1.0, 
  952.                         1.0, 0.0, 0.0, 0.0,
  953.                         obj->tex[col+i][0], obj->tex[col+i][1], 
  954.                         0.0, 0.0, 0.0, 0.0, 0.0, 0.0 );
  955.                 v++; n++;
  956.                 
  957.                 ST( *v, obj->screen[ncol+i][X], obj->screen[ncol+i][Y], obj->screen[ncol+i][Z], 1.0, 
  958.                         1.0, 0.0, 0.0, 0.0,
  959.                         obj->tex[ncol+i][0], obj->tex[ncol+i][1], 
  960.                         0.0, 0.0, 0.0, 0.0, 0.0, 0.0 );
  961.                 v++; n++;
  962.             }
  963.             
  964.             obj->num_strips++;
  965.         }
  966.         
  967.         obj->num_verts_per_strip = 2*(NUM_STEPS+1);
  968.     }
  969.     else
  970.     {
  971.         for( j = 0; j < NUM_STEPS; j++ )
  972.         {
  973.             col = j*(NUM_STEPS+1);
  974.             ncol = col + (NUM_STEPS+1);
  975.             
  976.             for( i = 0; i < NUM_STEPS; i++ )
  977.             {
  978.                 /*
  979.                  * lower left triangle
  980.                  */
  981.                 ST( *v, obj->screen[col+i+1][X], obj->screen[col+i+1][Y], obj->screen[col+i+1][Z], 1.0, 
  982.                         1.0, 0.0, 0.0, 0.0,
  983.                         obj->tex[col+i+1][0], obj->tex[col+i+1][1], 
  984.                         0.0, 0.0, 0.0, 0.0, 0.0, 0.0 );
  985.                 v++; n++;
  986.                 
  987.                 ST( *v, obj->screen[ncol+i+1][X], obj->screen[ncol+i+1][Y], obj->screen[ncol+i+1][Z], 1.0, 
  988.                         1.0, 0.0, 0.0, 0.0,
  989.                         obj->tex[ncol+i+1][0], obj->tex[ncol+i+1][1], 
  990.                         0.0, 0.0, 0.0, 0.0, 0.0, 0.0 );
  991.                 v++; n++;
  992.                 
  993.                 ST( *v, obj->screen[col+i][X], obj->screen[col+i][Y], obj->screen[col+i][Z], 1.0, 
  994.                         1.0, 0.0, 0.0, 0.0,
  995.                         obj->tex[col+i][0], obj->tex[col+i][1], 
  996.                         0.0, 0.0, 0.0, 0.0, 0.0, 0.0 );
  997.                 v++; n++;
  998.                 
  999.                 /*
  1000.                  * upper right triangle
  1001.                  */
  1002.                 ST( *v, obj->screen[ncol+i+1][X], obj->screen[ncol+i+1][Y], obj->screen[ncol+i+1][Z], 1.0, 
  1003.                         1.0, 0.0, 0.0, 0.0,
  1004.                         obj->tex[ncol+i+1][0], obj->tex[ncol+i+1][1], 
  1005.                         0.0, 0.0, 0.0, 0.0, 0.0, 0.0 );
  1006.                 v++; n++;
  1007.                 
  1008.                 ST( *v, obj->screen[ncol+i][X], obj->screen[ncol+i][Y], obj->screen[ncol+i][Z], 1.0, 
  1009.                         1.0, 0.0, 0.0, 0.0,
  1010.                         obj->tex[ncol+i][0], obj->tex[ncol+i][1], 
  1011.                         0.0, 0.0, 0.0, 0.0, 0.0, 0.0 );
  1012.                 v++; n++;
  1013.                 
  1014.                 ST( *v, obj->screen[col+i][X], obj->screen[col+i][Y], obj->screen[col+i][Z], 1.0, 
  1015.                         1.0, 0.0, 0.0, 0.0,
  1016.                         obj->tex[col+i][0], obj->tex[col+i][1], 
  1017.                         0.0, 0.0, 0.0, 0.0, 0.0, 0.0 );
  1018.                 v++; n++;
  1019.             }
  1020.         }
  1021.         
  1022.         obj->num_strips                = 0;
  1023.         obj->num_verts_per_strip    = 0;
  1024.     }
  1025.     
  1026.     obj->num_rave_verts = n;
  1027. }
  1028.  
  1029. void transform( OBJECT *obj )
  1030. {
  1031.     for( int i = 0; i < obj->num_verts; i++ )
  1032.     {
  1033.         /*
  1034.          * rotate
  1035.          */
  1036.         vect_matrix_mult( obj->world[i], R, obj->world[i] );
  1037.         
  1038.         /*
  1039.          * project
  1040.          */
  1041.         vect_matrix_mult( obj->world[i], VPN, obj->screen[i] );
  1042.         homo_vect( obj->screen[i] );
  1043.     }
  1044. }
  1045.  
  1046. void render( OBJECT *obj )
  1047. {
  1048.     QARenderStart( gDrawContext, NULL, NULL );
  1049.     
  1050.     if( obj->num_strips > 0 )
  1051.     {
  1052.         for( int i = 0; i < obj->num_strips; i++ )
  1053.         {
  1054.             QADrawVTexture( gDrawContext, obj->num_verts_per_strip, kQAVertexMode_Strip,
  1055.                             obj->verts + i*obj->num_verts_per_strip, NULL );
  1056.         }
  1057.     }
  1058.     else
  1059.     {
  1060.         QADrawVTexture( gDrawContext, obj->num_rave_verts, kQAVertexMode_Tri, obj->verts, NULL );
  1061.     }
  1062.     
  1063.     QARenderEnd( gDrawContext, NULL );                
  1064. }
  1065.  
  1066. /****************************************************************/
  1067. /* matrix code                                                    */
  1068. /****************************************************************/
  1069. void matrix_mult( MATRIX mat1, MATRIX mat2, MATRIX result )
  1070. {
  1071.     int i, j, k;
  1072.     FLOAT32 tmp;
  1073.  
  1074.     for( i = 0; i < 4; i++ )
  1075.     {
  1076.         for( j = 0; j < 4; j++ )
  1077.         {
  1078.             tmp = 0.0;
  1079.             for( k = 0; k < 4; k++ )
  1080.                 tmp += mat1[i][k] * mat2[k][j];
  1081.             result[i][j] = tmp;
  1082.         }
  1083.     }
  1084. }
  1085.  
  1086. /******************************************************************/
  1087. void vect_matrix_mult( VECT pt, MATRIX mat, VECT result )
  1088. {
  1089.     int i, j;
  1090.     VECT r;
  1091.     
  1092.     for( i = 0; i < 4; i++ )
  1093.     {
  1094.         r[i] = 0.0;
  1095.         for( j = 0; j < 4; j++ )
  1096.             r[i] += mat[i][j] * pt[j];
  1097.     }
  1098.  
  1099.     copy_vect( result, r );
  1100. }
  1101.  
  1102. /******************************************************************/
  1103. void load_matrix_rows( MATRIX R, VECT row1, VECT row2, VECT row3 )
  1104. {
  1105.     int i;
  1106.  
  1107.     for( i = 0; i < 3; i++ )
  1108.     {
  1109.         R[0][i] = row1[i];
  1110.         R[1][i] = row2[i];
  1111.         R[2][i] = row3[i];
  1112.         R[3][i] = 0.0;
  1113.     }
  1114.  
  1115.     R[0][W] = 0.0;
  1116.     R[1][W] = 0.0;
  1117.     R[2][W] = 0.0;
  1118.     R[3][W] = 1.0;
  1119. }
  1120.  
  1121. /******************************************************************/
  1122. void set_view_matrix( MATRIX VPN, VECT lookat, VECT up, VECT eye, Rect *WinRect )
  1123. {
  1124.     VECT         n, u, v;
  1125.     MATRIX        R, invR, N, P, V, VP;
  1126.     MATRIX         T, S, VT, VS, VT2;
  1127.     MATRIX        PT, PS, TMP, TMP2;
  1128.     FLOAT32     dist, front, back;
  1129.     FLOAT32     umin, umax, vmin, vmax;
  1130.     FLOAT32     umid, vmid;
  1131.     FLOAT32     xscale, yscale, zscale; 
  1132.     FLOAT32     scr_xmin, scr_ymin;
  1133.     FLOAT32     scr_xmax, scr_ymax;
  1134.     FLOAT32     scr_xdelta, scr_ydelta;
  1135.     FLOAT32        new_dist, zmin, zmax;
  1136.     
  1137.     /*
  1138.      * the values in the file specify the distance of
  1139.      * the view plane and clipping planes from the eye
  1140.      * point. We negate all of them, because once
  1141.      * the eye is at the origin they will all be in
  1142.      * the negative z range.
  1143.      */
  1144.     dist     = 1.0;
  1145.     front     = 0.1;
  1146.     back     = 100.0;
  1147.  
  1148.     if( FLT_ZERO(dist) )
  1149.         dist = 0.1;
  1150.  
  1151.     umin     = -1.0;
  1152.     umax     = 1.0;
  1153.     vmin     = -1.0;
  1154.     vmax     = 1.0;
  1155.     umid     = (umin + umax)/2.0;
  1156.     vmid     = (vmin + vmax)/2.0;
  1157.  
  1158.     /*
  1159.      * initialize screen vieport min, max x,y values
  1160.      * as well as screen viewport x, y delta
  1161.      */
  1162.     scr_xmin     = WinRect->left;
  1163.     scr_xmax     = WinRect->right;
  1164.     scr_ymin     = WinRect->top;
  1165.     scr_ymax     = WinRect->bottom;
  1166.     scr_xdelta     = (scr_xmax - scr_xmin);
  1167.     scr_ydelta     = (scr_ymax - scr_ymin);
  1168.  
  1169.     /*
  1170.      * derive vector normal to view plane
  1171.      */
  1172.     sub_vect( eye, lookat, n );
  1173.     norm( n );
  1174.     norm( up );
  1175.  
  1176.     /*
  1177.      * generate view plane horizontal vector from
  1178.      * cross product of n and up vector
  1179.      */
  1180.     cross( up, n, u );
  1181.     norm( u );
  1182.  
  1183.     /*
  1184.      * generate true view plane up vector from
  1185.      * cross product of n and u vectors
  1186.      */
  1187.     cross( n, u, v );
  1188.     norm( v );
  1189.  
  1190.     /*
  1191.      * build rotation matrix from u, v, n
  1192.      * which are the vectors that will rotate
  1193.      * to become the world coordinate axes
  1194.      */
  1195.     ident_mat( R );
  1196.     load_matrix_rows( R, u, v, n );
  1197.     transpose_matrix( R, invR );
  1198.     
  1199.     /*
  1200.      * init translation of eye to world origin
  1201.      * and combine rotation, translation
  1202.      */    
  1203.     init_trans( T, -eye[X], -eye[Y], -eye[Z] );
  1204.  
  1205.     matrix_mult( R, T, TMP );
  1206.  
  1207.     /*
  1208.      * set up scale matrix for converting to
  1209.      * normalized coordinates for clipping
  1210.      * against canonical view frustum
  1211.      * (equation 6.39 Foley & VanDam p.269)
  1212.      */
  1213.     xscale = (2.0 * dist)/((umax - umin)*(dist+back));
  1214.     yscale = (2.0 * dist)/((vmax - vmin)*(dist+back));
  1215.     zscale = 1.0/(dist+back);
  1216.     
  1217.     init_scale( S, xscale, yscale, zscale );
  1218.     matrix_mult( S, TMP, N );
  1219.  
  1220.     /*
  1221.      * calculate new view distance & zmin 
  1222.      * (since they have been scaled by the
  1223.      * normalization transformation
  1224.      * (equation 6.40 Foley & VanDam p.270)
  1225.      */
  1226.     new_dist     = dist * zscale;
  1227.     zmin         = -(dist+front) * zscale;
  1228.     zmax         = -(dist+back) * zscale;
  1229.     
  1230.     /*
  1231.      * set up matrix to transform to parallel
  1232.      * projection canonical clip volume 
  1233.      * (equation 6.48 Foley & VanDam p.275)
  1234.      */
  1235.     ident_mat( P );
  1236.     P[3][Z] = 1.0/new_dist;
  1237.     P[3][W] = 0.0;
  1238.     
  1239.     /*
  1240.      * set up view transformation - here we are transforming
  1241.      * from normalized clip coordinates to screen coordinates
  1242.      * the clip coordinates range from -new_dist to +new_dist 
  1243.      * because this is what the view plane normalized to -
  1244.      * (equation 6.54 Foley & VanDam p.278)
  1245.      */    
  1246.     init_trans( VT, new_dist, new_dist, 0.0 );
  1247.     init_scale( VS, scr_xdelta/(2.0*new_dist), scr_ydelta/(2.0*new_dist), 1.0 );
  1248.     //init_trans( VT2, scr_xmin, scr_ymin, 0 );  RAVE takes care of this for us
  1249.  
  1250.     matrix_mult( VS, VT, V );
  1251.     matrix_mult( V, P, VP );
  1252.     matrix_mult( VP, N, VPN );
  1253. }
  1254.  
  1255. /*
  1256.  * Function:                                                    
  1257.  *      rotate_about_axis() -  generates 4x4 matrix    to perform    
  1258.  *        rotation by given angle (radians) around an arbitrary   
  1259.  *        axis, as described in "Graphics Gems" on p.465.         
  1260.  *                                                              
  1261.  * Inputs:                                                      
  1262.  *        axis    - VECT defining axis                            
  1263.  *        angle     - FLOAT32 defining angle of rotation in radians 
  1264.  *        M        - 4x4 matrix to receive result                    
  1265.  *                                                              
  1266.  * Returns:                                                     
  1267.  *      none                                                    
  1268.  */
  1269. void rotate_about_axis( VECT axis, FLOAT32 angle, MATRIX M )
  1270. {
  1271.     FLOAT32  sina, cosa, t;
  1272.     FLOAT32  x, y, z;
  1273.  
  1274.     norm( axis );
  1275.     x = axis[X];
  1276.     y = axis[Y];
  1277.     z = axis[Z];
  1278.   
  1279.     sina = sin( angle );
  1280.     cosa = cos( angle );
  1281.     t = 1.0 - cosa;
  1282.  
  1283.     ident_mat( M );
  1284.     M[0][0] = t * SQR(x) + cosa;
  1285.     M[0][1] = t * x * y + sina * z;
  1286.     M[0][2] = t * x * z - sina * y;
  1287.  
  1288.     M[1][0] = t * x * y - sina * z;
  1289.     M[1][1] = t * SQR(y) + cosa;
  1290.     M[1][2] = t * y * z + sina * x;
  1291.  
  1292.     M[2][0] = t * x * z + sina * y;
  1293.     M[2][1] = t * y * z - sina * x;
  1294.     M[2][2] = t * SQR(z) + cosa;
  1295. }
  1296.  
  1297.